package Concurrency2.Chapter02_InnerLockPrinciple;

import utils.MUtils;

import java.util.LinkedList;

/**
 * Instruction：实现生产者消费者模型
 * Author：@author MaLi
 */
public class T02_ProducerConsumer {
    private static final Object lock = new Object();

    public static class Producer implements Runnable {
        private DataContainer dataContainer;
        private int initSize;

        public Producer(DataContainer dataContainer, int initSize) {
            this.dataContainer = dataContainer;
            this.initSize = initSize;
        }

        @Override
        public void run() {
            //队列不满, 生产数据 --> 容器中添加数据
            synchronized (lock) {
                //队列满, 停止生产
                if (dataContainer.getSize() < initSize){
                    //生产数据
                    dataContainer.setData(Thread.currentThread().getName());
                    //通知其它线程来消费或者生产
                }
                notifyWait();
            }
        }
        private void notifyWait() {
            notifyAll();
            try {
                //释放锁
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static class Consumer implements Runnable {
        private DataContainer dataContainer;
        private int initSize;

        public Consumer(DataContainer dataContainer, int initSize) {
            this.dataContainer = dataContainer;
            this.initSize = initSize;
        }

        @Override
        public void run() {
            //队列不空, 消费数据
            synchronized (lock) {
                if (dataContainer.getSize() > 0) {
                    String data = dataContainer.getData();
                    MUtils.print(data);
                }
                notifyWait();
            }
        }

        private void notifyWait() {
            notifyAll();
            try {
                //释放锁
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    public static class DataContainer {
        private LinkedList<String> container;
        private int initSize;

        public DataContainer(int initSize) {
            this.container = new LinkedList<>();
            this.initSize = initSize;
        }

        public String getData() {
            return container.removeFirst();
        }

        public void setData(String data) {
            container.addLast(data);
        }

        public int getSize() {
            return this.container.size();
        }
    }
}
